This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

source("tianfengRwrappers.R")

heatmapTFs <- topTFs %>% group_by(seuratCluster) %>% slice_max(n = 2000, order_by = RelativeActivity)

top_regulonActivity <- regulonActivity[sapply(heatmapTFs$Regulon, function(e) {which(rownames(regulonActivity) == e)}), ]
# annotation_row <-  data.frame(cluster = factor(top5$seuratCluster), row.names = make.names(top5$Regulon,TRUE))
genes_to_show <- c(as.character(top5$Regulon), "PRDM6_extended (53g)","PRDM6 (51g)")


##获得基因和细胞聚类信息
cluster_info <- colnames(regulonActivity)

##筛选矩阵为要画热图的基因
mat <- top_regulonActivity

#获得要展示的基因在热图中的位置信息
gene_pos <- match(genes_to_show, rownames(mat))
row_anno <- rowAnnotation(gene=anno_mark(at=gene_pos,labels = genes_to_show))

col <- colors_list[c(4,2,3,1,5)]
names(col) <- cluster_info
top_anno <- HeatmapAnnotation(cluster=anno_block(gp=gpar(fill=col),labels = cluster_info,
                                                 labels_gp = gpar(cex=1,col='black'))) ## 顶端的cluster注释


col_fun <-  colorRamp2(c(-2, 0, 2), c("#1E90FF", "white", "#ff2121")) #颜色

svg("ds2TFs.svg",height = 6,width = 10)
Heatmap(mat, cluster_rows = FALSE, cluster_columns = FALSE, 
        show_column_names = FALSE, show_row_names = FALSE,
        column_split = cluster_info, top_annotation = top_anno,  
        column_title = NULL, right_annotation = row_anno, 
        heatmap_legend_param = list(
          title='Regulon Activity', title_position='leftcenter-rot'), col = col_fun)
Warning: The input is a data frame, convert it to the matrix.
dev.off()
null device 
          1 

ds1

regulonActivity <- read.csv("./ds1_SCENIC/regulonActivity.csv",row.names = 1)
topTFs <- read.csv("./ds1_SCENIC/topRegulators.csv")

regulonActivity <- regulonActivity[,levels(topTFs$seuratCluster)] #调换列顺序
# colnames(regulonActivity)[colnames(regulonActivity)=="T.cell"] <- "T cell"

top5 <- topTFs %>% group_by(seuratCluster) %>% slice_max(n = 5, order_by = RelativeActivity)

#根据已知的top5更新行顺序
top_regulonActivity <- regulonActivity[sapply(top5$Regulon, function(e) {which(rownames(regulonActivity) == e)}), ]


annotation_row <-  data.frame(cluster = factor(top5$seuratCluster), row.names = make.names(top5$Regulon,TRUE)) #make.names用来生成不冲突的行

pheatmap(top_regulonActivity, breaks = unique(c(seq(-2,2, length=400))), 
                 color = colorRampPalette(c("#1E90FF", "white", "#ff2121"))(400),
                border_color = NA, cluster_rows = FALSE, cluster_cols = FALSE,
                main = "regulonActivity",angle_col = 45, show_rownames = T)

# ggsave("TFs_activity.png",device = png,width = 10,height = 8,plot = TFs_heatmap)
heatmapTFs <- topTFs %>% group_by(seuratCluster) %>% slice_max(n = 2000, order_by = RelativeActivity)

top_regulonActivity <- regulonActivity[sapply(heatmapTFs$Regulon, function(e) {which(rownames(regulonActivity) == e)}), ]
# annotation_row <-  data.frame(cluster = factor(top5$seuratCluster), row.names = make.names(top5$Regulon,TRUE))
genes_to_show <- c(as.character(top5$Regulon),"DLX6_extended (43g)","DLX2 (18g)")##对齐
##获得基因和细胞聚类信息
cluster_info <- colnames(regulonActivity)

##筛选矩阵为要画热图的基因
mat <- top_regulonActivity

#获得要展示的基因在热图中的位置信息
gene_pos <- match(genes_to_show, rownames(mat))
row_anno <- rowAnnotation(gene=anno_mark(at=gene_pos,labels = genes_to_show))

col <- colors_list[c(2,1,5,8)]
names(col) <- cluster_info
top_anno <- HeatmapAnnotation(cluster=anno_block(gp=gpar(fill=col),labels = cluster_info,
                                                 labels_gp = gpar(cex=1,col='black'))) ## 顶端的cluster注释


col_fun <-  colorRamp2(c(-2, 0, 2), c("#1E90FF", "white", "#ff2121")) #颜色

svg("ds1TFs.svg",height = 6,width = 10)
Heatmap(mat, cluster_rows = FALSE, cluster_columns = FALSE, 
        show_column_names = FALSE, show_row_names = FALSE,
        column_split = cluster_info, top_annotation = top_anno,  
        column_title = NULL, right_annotation = row_anno, 
        heatmap_legend_param = list(
          title='Regulon Activity', title_position='leftcenter-rot'), col = col_fun)
Warning: The input is a data frame, convert it to the matrix.
dev.off()
null device 
          1 
library(Seurat)
library(SCENIC)
library(AUCell)
library(RcisTarget)
library(SCopeLoomR)
library(dplyr)
library(foreach)
lamb <- function(s1,s2)
{
  paste0(s2,s1)
}

fileloc <- scenicOptions@fileNames

temp <- lapply(fileloc[["output"]],lamb,"ds2_SCENIC/") %>% as.character() %>% as.matrix()
rownames(temp) <- rownames(fileloc[["output"]])
colnames(temp) <- "fileName"
fileloc[["output"]] <- temp

temp <- lapply(fileloc[["int"]],lamb,"ds2_SCENIC/") %>% as.character() %>% as.matrix()
rownames(temp) <- rownames(fileloc[["int"]])
colnames(temp) <- "fileName"
fileloc[["int"]] <- temp

scenicOptions@fileNames <- fileloc
scenicOptions@settings[["tSNE_filePrefix"]] <- "ds2_SCENIC/int/tSNE"

regulonAUC <- loadInt(scenicOptions, "aucell_regulonAUC")
regulonActivity_byCellType <- sapply(
  split(rownames(cellInfo), cellInfo$CellType),
  function(cells) rowMeans(getAUC(regulonAUC)[, cells])
)

regulonActivity_byCellType_Scaled <- t(scale(t(regulonActivity_byCellType), center = T, scale = T))
topRegulators <- reshape2::melt(regulonActivity_byCellType_Scaled)
colnames(topRegulators) <- c("Regulon", "seuratCluster", "RelativeActivity")
topRegulators <- topRegulators[which(topRegulators$RelativeActivity > 0), ]

aucellApp <- plotTsne_AUCellApp(scenicOptions, logMat)

savedSelections <- shiny::runApp(aucellApp)

Listening on http://127.0.0.1:7492
DLX5_extended (13g) threshold replaced by 0.15
DLX6_extended (21g) threshold replaced by 0.085
App stopped. Returning the thresholds & cells selected.
runSCENIC_4_aucell_binarize(scenicOptions)
Binary regulon activity: 172 TF regulons x 9537 cells.
(172 regulons including 'extended' versions)
154 regulons are active in more than 1% (95.37) cells.

ds1

fileloc <- scenicOptions@fileNames

temp <- lapply(fileloc[["output"]],lamb,"ds1_SCENIC/") %>% as.character() %>% as.matrix()
rownames(temp) <- rownames(fileloc[["output"]])
colnames(temp) <- "fileName"
fileloc[["output"]] <- temp

temp <- lapply(fileloc[["int"]],lamb,"ds1_SCENIC/") %>% as.character() %>% as.matrix()
rownames(temp) <- rownames(fileloc[["int"]])
colnames(temp) <- "fileName"
fileloc[["int"]] <- temp

scenicOptions@fileNames <- fileloc
scenicOptions@settings[["tSNE_filePrefix"]] <- "ds1_SCENIC/int/tSNE"

regulonAUC <- loadInt(scenicOptions, "aucell_regulonAUC")
regulonActivity_byCellType <- sapply(
  split(rownames(cellInfo), cellInfo$CellType),
  function(cells) rowMeans(getAUC(regulonAUC)[, cells])
)

regulonActivity_byCellType_Scaled <- t(scale(t(regulonActivity_byCellType), center = T, scale = T))
topRegulators <- reshape2::melt(regulonActivity_byCellType_Scaled)
colnames(topRegulators) <- c("Regulon", "seuratCluster", "RelativeActivity")
topRegulators <- topRegulators[which(topRegulators$RelativeActivity > 0), ]

aucellApp <- plotTsne_AUCellApp(scenicOptions, logMat)

savedSelections <- shiny::runApp(aucellApp)


plotTsne_AUCellHtml(scenicOptions, logMat,"ds1_scenic")
newThresholds <- savedSelections$thresholds
scenicOptions@fileNames$int["aucell_thresholds", 1] <- "ds1_SCENIC/int/newThresholds2.Rds"
saveRDS(newThresholds, file = getIntName(scenicOptions, "aucell_thresholds"))
saveRDS(scenicOptions, file = "ds1_SCENIC/int/scenicOptions.Rds")
#save.image()

runSCENIC_4_aucell_binarize(scenicOptions)

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ3RybCtTaGlmdCtFbnRlciouIApgYGB7cn0Kc291cmNlKCJ0aWFuZmVuZ1J3cmFwcGVycy5SIikKYGBgCgoKYGBge3J9CnJlZ3Vsb25BY3Rpdml0eSA8LSByZWFkLmNzdigiLi9kczJfU0NFTklDL3JlZ3Vsb25BY3Rpdml0eS5jc3YiLHJvdy5uYW1lcyA9IDEpCnRvcFRGcyA8LSByZWFkLmNzdigiLi9kczJfU0NFTklDL3RvcFJlZ3VsYXRvcnMuY3N2IikKdG9wVEZzWyh0b3BURnMkUmVndWxvbj09IlBSRE02X2V4dGVuZGVkICg1M2cpIiB8IHRvcFRGcyRSZWd1bG9uPT0iUFJETTYgKDUxZykiKSZ0b3BURnMkc2V1cmF0Q2x1c3RlciA9PSAiU01DMSIsXSA8LSBOQSAgIyMg5Yig6Zmk54m55a6a6KGM77yMU01DMueahOW8uuW6puimgeWkp+S6jlNNQzHvvIzmlL7liLBTTUMy6YKj6YeM6KGo56S6CnRvcFRGczwtbmEub21pdCh0b3BURnMpCnJlZ3Vsb25BY3Rpdml0eSA8LSByZWd1bG9uQWN0aXZpdHlbLGxldmVscyh0b3BURnMkc2V1cmF0Q2x1c3RlcildICPosIPmjaLliJfpobrluo8KCiMgY29sbmFtZXMocmVndWxvbkFjdGl2aXR5KVtjb2xuYW1lcyhyZWd1bG9uQWN0aXZpdHkpPT0iVC5jZWxsIl0gPC0gIlQgY2VsbCIKCnRvcDUgPC0gdG9wVEZzICU+JSBncm91cF9ieShzZXVyYXRDbHVzdGVyKSAlPiUgc2xpY2VfbWF4KG4gPSA1LCBvcmRlcl9ieSA9IFJlbGF0aXZlQWN0aXZpdHkpCgoj5qC55o2u5bey55+l55qEdG9wNeabtOaWsOihjOmhuuW6jwp0b3BfcmVndWxvbkFjdGl2aXR5IDwtIHJlZ3Vsb25BY3Rpdml0eVtzYXBwbHkodG9wNSRSZWd1bG9uLCBmdW5jdGlvbihlKSB7d2hpY2gocm93bmFtZXMocmVndWxvbkFjdGl2aXR5KSA9PSBlKX0pLCBdCgoKYW5ub3RhdGlvbl9yb3cgPC0gIGRhdGEuZnJhbWUoY2x1c3RlciA9IGZhY3Rvcih0b3A1JHNldXJhdENsdXN0ZXIpLCByb3cubmFtZXMgPSBtYWtlLm5hbWVzKHRvcDUkUmVndWxvbixUUlVFKSkgI21ha2UubmFtZXPnlKjmnaXnlJ/miJDkuI3lhrLnqoHnmoTooYwKClRGc19oZWF0bWFwIDwtIHBoZWF0bWFwKHRvcF9yZWd1bG9uQWN0aXZpdHksIGJyZWFrcyA9IHVuaXF1ZShjKHNlcSgtMiwyLCBsZW5ndGg9NDAwKSkpLCAKICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYygiIzFFOTBGRiIsICJ3aGl0ZSIsICIjZmYyMTIxIikpKDQwMCksCiAgICAgICAgICAgICAgICBib3JkZXJfY29sb3IgPSBOQSwgY2x1c3Rlcl9yb3dzID0gRkFMU0UsIGNsdXN0ZXJfY29scyA9IEZBTFNFLAogICAgICAgICAgICAgICAgbWFpbiA9ICJyZWd1bG9uQWN0aXZpdHkiLGFuZ2xlX2NvbCA9IDQ1LCBzaG93X3Jvd25hbWVzID0gVCkKIyBnZ3NhdmUoIlRGc19hY3Rpdml0eS5wbmciLGRldmljZSA9IHBuZyx3aWR0aCA9IDEwLGhlaWdodCA9IDgscGxvdCA9IFRGc19oZWF0bWFwKQoKVEZzX2hlYXRtYXAKYGBgCgpgYGB7cn0KaGVhdG1hcFRGcyA8LSB0b3BURnMgJT4lIGdyb3VwX2J5KHNldXJhdENsdXN0ZXIpICU+JSBzbGljZV9tYXgobiA9IDIwMDAsIG9yZGVyX2J5ID0gUmVsYXRpdmVBY3Rpdml0eSkKCnRvcF9yZWd1bG9uQWN0aXZpdHkgPC0gcmVndWxvbkFjdGl2aXR5W3NhcHBseShoZWF0bWFwVEZzJFJlZ3Vsb24sIGZ1bmN0aW9uKGUpIHt3aGljaChyb3duYW1lcyhyZWd1bG9uQWN0aXZpdHkpID09IGUpfSksIF0KIyBhbm5vdGF0aW9uX3JvdyA8LSAgZGF0YS5mcmFtZShjbHVzdGVyID0gZmFjdG9yKHRvcDUkc2V1cmF0Q2x1c3RlciksIHJvdy5uYW1lcyA9IG1ha2UubmFtZXModG9wNSRSZWd1bG9uLFRSVUUpKQpnZW5lc190b19zaG93IDwtIGMoYXMuY2hhcmFjdGVyKHRvcDUkUmVndWxvbiksICJQUkRNNl9leHRlbmRlZCAoNTNnKSIsIlBSRE02ICg1MWcpIikKCgojI+iOt+W+l+WfuuWboOWSjOe7huiDnuiBmuexu+S/oeaBrwpjbHVzdGVyX2luZm8gPC0gY29sbmFtZXMocmVndWxvbkFjdGl2aXR5KQoKIyPnrZvpgInnn6npmLXkuLropoHnlLvng63lm77nmoTln7rlm6AKbWF0IDwtIHRvcF9yZWd1bG9uQWN0aXZpdHkKCiPojrflvpfopoHlsZXnpLrnmoTln7rlm6DlnKjng63lm77kuK3nmoTkvY3nva7kv6Hmga8KZ2VuZV9wb3MgPC0gbWF0Y2goZ2VuZXNfdG9fc2hvdywgcm93bmFtZXMobWF0KSkKcm93X2Fubm8gPC0gcm93QW5ub3RhdGlvbihnZW5lPWFubm9fbWFyayhhdD1nZW5lX3BvcyxsYWJlbHMgPSBnZW5lc190b19zaG93KSkKCmNvbCA8LSBjb2xvcnNfbGlzdFtjKDQsMiwzLDEsNSldCm5hbWVzKGNvbCkgPC0gY2x1c3Rlcl9pbmZvCnRvcF9hbm5vIDwtIEhlYXRtYXBBbm5vdGF0aW9uKGNsdXN0ZXI9YW5ub19ibG9jayhncD1ncGFyKGZpbGw9Y29sKSxsYWJlbHMgPSBjbHVzdGVyX2luZm8sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHNfZ3AgPSBncGFyKGNleD0xLGNvbD0nYmxhY2snKSkpICMjIOmhtuerr+eahGNsdXN0ZXLms6jph4oKCgpjb2xfZnVuIDwtICBjb2xvclJhbXAyKGMoLTIsIDAsIDIpLCBjKCIjMUU5MEZGIiwgIndoaXRlIiwgIiNmZjIxMjEiKSkgI+minOiJsgoKc3ZnKCJkczJURnMuc3ZnIixoZWlnaHQgPSA2LHdpZHRoID0gMTApCkhlYXRtYXAobWF0LCBjbHVzdGVyX3Jvd3MgPSBGQUxTRSwgY2x1c3Rlcl9jb2x1bW5zID0gRkFMU0UsIAogICAgICAgIHNob3dfY29sdW1uX25hbWVzID0gRkFMU0UsIHNob3dfcm93X25hbWVzID0gRkFMU0UsCiAgICAgICAgY29sdW1uX3NwbGl0ID0gY2x1c3Rlcl9pbmZvLCB0b3BfYW5ub3RhdGlvbiA9IHRvcF9hbm5vLCAgCiAgICAgICAgY29sdW1uX3RpdGxlID0gTlVMTCwgcmlnaHRfYW5ub3RhdGlvbiA9IHJvd19hbm5vLCAKICAgICAgICBoZWF0bWFwX2xlZ2VuZF9wYXJhbSA9IGxpc3QoCiAgICAgICAgICB0aXRsZT0nUmVndWxvbiBBY3Rpdml0eScsIHRpdGxlX3Bvc2l0aW9uPSdsZWZ0Y2VudGVyLXJvdCcpLCBjb2wgPSBjb2xfZnVuKQpkZXYub2ZmKCkKYGBgCgpgYGB7cn0KdG9wX3JlZ3Vsb25BY3Rpdml0eVtoZWF0bWFwVEZzJFJlZ3Vsb24sXQpoZWF0bWFwVEZzJFJlZ3Vsb24KdG9wX3JlZ3Vsb25BY3Rpdml0eQpzdWJzZXQodG9wX3JlZ3Vsb25BY3Rpdml0eSkKYGBgCgoKIyMgZHMxCmBgYHtyfQpyZWd1bG9uQWN0aXZpdHkgPC0gcmVhZC5jc3YoIi4vZHMxX1NDRU5JQy9yZWd1bG9uQWN0aXZpdHkuY3N2Iixyb3cubmFtZXMgPSAxKQp0b3BURnMgPC0gcmVhZC5jc3YoIi4vZHMxX1NDRU5JQy90b3BSZWd1bGF0b3JzLmNzdiIpCgpyZWd1bG9uQWN0aXZpdHkgPC0gcmVndWxvbkFjdGl2aXR5WyxsZXZlbHModG9wVEZzJHNldXJhdENsdXN0ZXIpXSAj6LCD5o2i5YiX6aG65bqPCiMgY29sbmFtZXMocmVndWxvbkFjdGl2aXR5KVtjb2xuYW1lcyhyZWd1bG9uQWN0aXZpdHkpPT0iVC5jZWxsIl0gPC0gIlQgY2VsbCIKCnRvcDUgPC0gdG9wVEZzICU+JSBncm91cF9ieShzZXVyYXRDbHVzdGVyKSAlPiUgc2xpY2VfbWF4KG4gPSA1LCBvcmRlcl9ieSA9IFJlbGF0aXZlQWN0aXZpdHkpCgoj5qC55o2u5bey55+l55qEdG9wNeabtOaWsOihjOmhuuW6jwp0b3BfcmVndWxvbkFjdGl2aXR5IDwtIHJlZ3Vsb25BY3Rpdml0eVtzYXBwbHkodG9wNSRSZWd1bG9uLCBmdW5jdGlvbihlKSB7d2hpY2gocm93bmFtZXMocmVndWxvbkFjdGl2aXR5KSA9PSBlKX0pLCBdCgoKYW5ub3RhdGlvbl9yb3cgPC0gIGRhdGEuZnJhbWUoY2x1c3RlciA9IGZhY3Rvcih0b3A1JHNldXJhdENsdXN0ZXIpLCByb3cubmFtZXMgPSBtYWtlLm5hbWVzKHRvcDUkUmVndWxvbixUUlVFKSkgI21ha2UubmFtZXPnlKjmnaXnlJ/miJDkuI3lhrLnqoHnmoTooYwKCnBoZWF0bWFwKHRvcF9yZWd1bG9uQWN0aXZpdHksIGJyZWFrcyA9IHVuaXF1ZShjKHNlcSgtMiwyLCBsZW5ndGg9NDAwKSkpLCAKICAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yUmFtcFBhbGV0dGUoYygiIzFFOTBGRiIsICJ3aGl0ZSIsICIjZmYyMTIxIikpKDQwMCksCiAgICAgICAgICAgICAgICBib3JkZXJfY29sb3IgPSBOQSwgY2x1c3Rlcl9yb3dzID0gRkFMU0UsIGNsdXN0ZXJfY29scyA9IEZBTFNFLAogICAgICAgICAgICAgICAgbWFpbiA9ICJyZWd1bG9uQWN0aXZpdHkiLGFuZ2xlX2NvbCA9IDQ1LCBzaG93X3Jvd25hbWVzID0gVCkKIyBnZ3NhdmUoIlRGc19hY3Rpdml0eS5wbmciLGRldmljZSA9IHBuZyx3aWR0aCA9IDEwLGhlaWdodCA9IDgscGxvdCA9IFRGc19oZWF0bWFwKQoKCmBgYAoKYGBge3J9CmhlYXRtYXBURnMgPC0gdG9wVEZzICU+JSBncm91cF9ieShzZXVyYXRDbHVzdGVyKSAlPiUgc2xpY2VfbWF4KG4gPSAyMDAwLCBvcmRlcl9ieSA9IFJlbGF0aXZlQWN0aXZpdHkpCgp0b3BfcmVndWxvbkFjdGl2aXR5IDwtIHJlZ3Vsb25BY3Rpdml0eVtzYXBwbHkoaGVhdG1hcFRGcyRSZWd1bG9uLCBmdW5jdGlvbihlKSB7d2hpY2gocm93bmFtZXMocmVndWxvbkFjdGl2aXR5KSA9PSBlKX0pLCBdCiMgYW5ub3RhdGlvbl9yb3cgPC0gIGRhdGEuZnJhbWUoY2x1c3RlciA9IGZhY3Rvcih0b3A1JHNldXJhdENsdXN0ZXIpLCByb3cubmFtZXMgPSBtYWtlLm5hbWVzKHRvcDUkUmVndWxvbixUUlVFKSkKZ2VuZXNfdG9fc2hvdyA8LSBjKGFzLmNoYXJhY3Rlcih0b3A1JFJlZ3Vsb24pLCJETFg2X2V4dGVuZGVkICg0M2cpIiwiRExYMiAoMThnKSIpIyPlr7npvZAKIyPojrflvpfln7rlm6Dlkoznu4bog57ogZrnsbvkv6Hmga8KY2x1c3Rlcl9pbmZvIDwtIGNvbG5hbWVzKHJlZ3Vsb25BY3Rpdml0eSkKCiMj562b6YCJ55+p6Zi15Li66KaB55S754Ot5Zu+55qE5Z+65ZugCm1hdCA8LSB0b3BfcmVndWxvbkFjdGl2aXR5Cgoj6I635b6X6KaB5bGV56S655qE5Z+65Zug5Zyo54Ot5Zu+5Lit55qE5L2N572u5L+h5oGvCmdlbmVfcG9zIDwtIG1hdGNoKGdlbmVzX3RvX3Nob3csIHJvd25hbWVzKG1hdCkpCnJvd19hbm5vIDwtIHJvd0Fubm90YXRpb24oZ2VuZT1hbm5vX21hcmsoYXQ9Z2VuZV9wb3MsbGFiZWxzID0gZ2VuZXNfdG9fc2hvdykpCgpjb2wgPC0gY29sb3JzX2xpc3RbYygyLDEsNSw4KV0KbmFtZXMoY29sKSA8LSBjbHVzdGVyX2luZm8KdG9wX2Fubm8gPC0gSGVhdG1hcEFubm90YXRpb24oY2x1c3Rlcj1hbm5vX2Jsb2NrKGdwPWdwYXIoZmlsbD1jb2wpLGxhYmVscyA9IGNsdXN0ZXJfaW5mbywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsc19ncCA9IGdwYXIoY2V4PTEsY29sPSdibGFjaycpKSkgIyMg6aG256uv55qEY2x1c3RlcuazqOmHigoKCmNvbF9mdW4gPC0gIGNvbG9yUmFtcDIoYygtMiwgMCwgMiksIGMoIiMxRTkwRkYiLCAid2hpdGUiLCAiI2ZmMjEyMSIpKSAj6aKc6ImyCgpzdmcoImRzMVRGcy5zdmciLGhlaWdodCA9IDYsd2lkdGggPSAxMCkKSGVhdG1hcChtYXQsIGNsdXN0ZXJfcm93cyA9IEZBTFNFLCBjbHVzdGVyX2NvbHVtbnMgPSBGQUxTRSwgCiAgICAgICAgc2hvd19jb2x1bW5fbmFtZXMgPSBGQUxTRSwgc2hvd19yb3dfbmFtZXMgPSBGQUxTRSwKICAgICAgICBjb2x1bW5fc3BsaXQgPSBjbHVzdGVyX2luZm8sIHRvcF9hbm5vdGF0aW9uID0gdG9wX2Fubm8sICAKICAgICAgICBjb2x1bW5fdGl0bGUgPSBOVUxMLCByaWdodF9hbm5vdGF0aW9uID0gcm93X2Fubm8sIAogICAgICAgIGhlYXRtYXBfbGVnZW5kX3BhcmFtID0gbGlzdCgKICAgICAgICAgIHRpdGxlPSdSZWd1bG9uIEFjdGl2aXR5JywgdGl0bGVfcG9zaXRpb249J2xlZnRjZW50ZXItcm90JyksIGNvbCA9IGNvbF9mdW4pCmRldi5vZmYoKQpgYGAKCgpgYGB7cn0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkoU0NFTklDKQpsaWJyYXJ5KEFVQ2VsbCkKbGlicmFyeShSY2lzVGFyZ2V0KQpsaWJyYXJ5KFNDb3BlTG9vbVIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZm9yZWFjaCkKYGBgCgoKYGBge3J9CmxhbWIgPC0gZnVuY3Rpb24oczEsczIpCnsKICBwYXN0ZTAoczIsczEpCn0KCmZpbGVsb2MgPC0gc2NlbmljT3B0aW9uc0BmaWxlTmFtZXMKCnRlbXAgPC0gbGFwcGx5KGZpbGVsb2NbWyJvdXRwdXQiXV0sbGFtYiwiZHMyX1NDRU5JQy8iKSAlPiUgYXMuY2hhcmFjdGVyKCkgJT4lIGFzLm1hdHJpeCgpCnJvd25hbWVzKHRlbXApIDwtIHJvd25hbWVzKGZpbGVsb2NbWyJvdXRwdXQiXV0pCmNvbG5hbWVzKHRlbXApIDwtICJmaWxlTmFtZSIKZmlsZWxvY1tbIm91dHB1dCJdXSA8LSB0ZW1wCgp0ZW1wIDwtIGxhcHBseShmaWxlbG9jW1siaW50Il1dLGxhbWIsImRzMl9TQ0VOSUMvIikgJT4lIGFzLmNoYXJhY3RlcigpICU+JSBhcy5tYXRyaXgoKQpyb3duYW1lcyh0ZW1wKSA8LSByb3duYW1lcyhmaWxlbG9jW1siaW50Il1dKQpjb2xuYW1lcyh0ZW1wKSA8LSAiZmlsZU5hbWUiCmZpbGVsb2NbWyJpbnQiXV0gPC0gdGVtcAoKc2NlbmljT3B0aW9uc0BmaWxlTmFtZXMgPC0gZmlsZWxvYwpzY2VuaWNPcHRpb25zQHNldHRpbmdzW1sidFNORV9maWxlUHJlZml4Il1dIDwtICJkczJfU0NFTklDL2ludC90U05FIgoKcmVndWxvbkFVQyA8LSBsb2FkSW50KHNjZW5pY09wdGlvbnMsICJhdWNlbGxfcmVndWxvbkFVQyIpCnJlZ3Vsb25BY3Rpdml0eV9ieUNlbGxUeXBlIDwtIHNhcHBseSgKICBzcGxpdChyb3duYW1lcyhjZWxsSW5mbyksIGNlbGxJbmZvJENlbGxUeXBlKSwKICBmdW5jdGlvbihjZWxscykgcm93TWVhbnMoZ2V0QVVDKHJlZ3Vsb25BVUMpWywgY2VsbHNdKQopCgpyZWd1bG9uQWN0aXZpdHlfYnlDZWxsVHlwZV9TY2FsZWQgPC0gdChzY2FsZSh0KHJlZ3Vsb25BY3Rpdml0eV9ieUNlbGxUeXBlKSwgY2VudGVyID0gVCwgc2NhbGUgPSBUKSkKdG9wUmVndWxhdG9ycyA8LSByZXNoYXBlMjo6bWVsdChyZWd1bG9uQWN0aXZpdHlfYnlDZWxsVHlwZV9TY2FsZWQpCmNvbG5hbWVzKHRvcFJlZ3VsYXRvcnMpIDwtIGMoIlJlZ3Vsb24iLCAic2V1cmF0Q2x1c3RlciIsICJSZWxhdGl2ZUFjdGl2aXR5IikKdG9wUmVndWxhdG9ycyA8LSB0b3BSZWd1bGF0b3JzW3doaWNoKHRvcFJlZ3VsYXRvcnMkUmVsYXRpdmVBY3Rpdml0eSA+IDApLCBdCgphdWNlbGxBcHAgPC0gcGxvdFRzbmVfQVVDZWxsQXBwKHNjZW5pY09wdGlvbnMsIGxvZ01hdCkKCnNhdmVkU2VsZWN0aW9ucyA8LSBzaGlueTo6cnVuQXBwKGF1Y2VsbEFwcCkKCgoKYGBgCgpgYGB7cn0KbmV3VGhyZXNob2xkcyA8LSBzYXZlZFNlbGVjdGlvbnMkdGhyZXNob2xkcwpzY2VuaWNPcHRpb25zQGZpbGVOYW1lcyRpbnRbImF1Y2VsbF90aHJlc2hvbGRzIiwgMV0gPC0gImRzMl9TQ0VOSUMvaW50L25ld1RocmVzaG9sZHMyLlJkcyIKc2F2ZVJEUyhuZXdUaHJlc2hvbGRzLCBmaWxlID0gZ2V0SW50TmFtZShzY2VuaWNPcHRpb25zLCAiYXVjZWxsX3RocmVzaG9sZHMiKSkKc2F2ZVJEUyhzY2VuaWNPcHRpb25zLCBmaWxlID0gImRzMl9TQ0VOSUMvaW50L3NjZW5pY09wdGlvbnMuUmRzIikKCnBsb3RUc25lX0FVQ2VsbEh0bWwoc2NlbmljT3B0aW9ucywgbG9nTWF0LCJkczJfc2NlbmljIikKcnVuU0NFTklDXzRfYXVjZWxsX2JpbmFyaXplKHNjZW5pY09wdGlvbnMpCmBgYAoKCiMgZHMxCmBgYHtyfQpmaWxlbG9jIDwtIHNjZW5pY09wdGlvbnNAZmlsZU5hbWVzCgp0ZW1wIDwtIGxhcHBseShmaWxlbG9jW1sib3V0cHV0Il1dLGxhbWIsImRzMV9TQ0VOSUMvIikgJT4lIGFzLmNoYXJhY3RlcigpICU+JSBhcy5tYXRyaXgoKQpyb3duYW1lcyh0ZW1wKSA8LSByb3duYW1lcyhmaWxlbG9jW1sib3V0cHV0Il1dKQpjb2xuYW1lcyh0ZW1wKSA8LSAiZmlsZU5hbWUiCmZpbGVsb2NbWyJvdXRwdXQiXV0gPC0gdGVtcAoKdGVtcCA8LSBsYXBwbHkoZmlsZWxvY1tbImludCJdXSxsYW1iLCJkczFfU0NFTklDLyIpICU+JSBhcy5jaGFyYWN0ZXIoKSAlPiUgYXMubWF0cml4KCkKcm93bmFtZXModGVtcCkgPC0gcm93bmFtZXMoZmlsZWxvY1tbImludCJdXSkKY29sbmFtZXModGVtcCkgPC0gImZpbGVOYW1lIgpmaWxlbG9jW1siaW50Il1dIDwtIHRlbXAKCnNjZW5pY09wdGlvbnNAZmlsZU5hbWVzIDwtIGZpbGVsb2MKc2NlbmljT3B0aW9uc0BzZXR0aW5nc1tbInRTTkVfZmlsZVByZWZpeCJdXSA8LSAiZHMxX1NDRU5JQy9pbnQvdFNORSIKCnJlZ3Vsb25BVUMgPC0gbG9hZEludChzY2VuaWNPcHRpb25zLCAiYXVjZWxsX3JlZ3Vsb25BVUMiKQpyZWd1bG9uQWN0aXZpdHlfYnlDZWxsVHlwZSA8LSBzYXBwbHkoCiAgc3BsaXQocm93bmFtZXMoY2VsbEluZm8pLCBjZWxsSW5mbyRDZWxsVHlwZSksCiAgZnVuY3Rpb24oY2VsbHMpIHJvd01lYW5zKGdldEFVQyhyZWd1bG9uQVVDKVssIGNlbGxzXSkKKQoKcmVndWxvbkFjdGl2aXR5X2J5Q2VsbFR5cGVfU2NhbGVkIDwtIHQoc2NhbGUodChyZWd1bG9uQWN0aXZpdHlfYnlDZWxsVHlwZSksIGNlbnRlciA9IFQsIHNjYWxlID0gVCkpCnRvcFJlZ3VsYXRvcnMgPC0gcmVzaGFwZTI6Om1lbHQocmVndWxvbkFjdGl2aXR5X2J5Q2VsbFR5cGVfU2NhbGVkKQpjb2xuYW1lcyh0b3BSZWd1bGF0b3JzKSA8LSBjKCJSZWd1bG9uIiwgInNldXJhdENsdXN0ZXIiLCAiUmVsYXRpdmVBY3Rpdml0eSIpCnRvcFJlZ3VsYXRvcnMgPC0gdG9wUmVndWxhdG9yc1t3aGljaCh0b3BSZWd1bGF0b3JzJFJlbGF0aXZlQWN0aXZpdHkgPiAwKSwgXQoKYXVjZWxsQXBwIDwtIHBsb3RUc25lX0FVQ2VsbEFwcChzY2VuaWNPcHRpb25zLCBsb2dNYXQpCgpzYXZlZFNlbGVjdGlvbnMgPC0gc2hpbnk6OnJ1bkFwcChhdWNlbGxBcHApCgoKcGxvdFRzbmVfQVVDZWxsSHRtbChzY2VuaWNPcHRpb25zLCBsb2dNYXQsImRzMV9zY2VuaWMiKQpgYGAKCmBgYHtyfQpuZXdUaHJlc2hvbGRzIDwtIHNhdmVkU2VsZWN0aW9ucyR0aHJlc2hvbGRzCnNjZW5pY09wdGlvbnNAZmlsZU5hbWVzJGludFsiYXVjZWxsX3RocmVzaG9sZHMiLCAxXSA8LSAiZHMxX1NDRU5JQy9pbnQvbmV3VGhyZXNob2xkczIuUmRzIgpzYXZlUkRTKG5ld1RocmVzaG9sZHMsIGZpbGUgPSBnZXRJbnROYW1lKHNjZW5pY09wdGlvbnMsICJhdWNlbGxfdGhyZXNob2xkcyIpKQpzYXZlUkRTKHNjZW5pY09wdGlvbnMsIGZpbGUgPSAiZHMxX1NDRU5JQy9pbnQvc2NlbmljT3B0aW9ucy5SZHMiKQojc2F2ZS5pbWFnZSgpCgpydW5TQ0VOSUNfNF9hdWNlbGxfYmluYXJpemUoc2NlbmljT3B0aW9ucykKYGBgCkFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZyB0aGUgKkluc2VydCBDaHVuayogYnV0dG9uIG9uIHRoZSB0b29sYmFyIG9yIGJ5IHByZXNzaW5nICpDdHJsK0FsdCtJKi4KCldoZW4geW91IHNhdmUgdGhlIG5vdGVib29rLCBhbiBIVE1MIGZpbGUgY29udGFpbmluZyB0aGUgY29kZSBhbmQgb3V0cHV0IHdpbGwgYmUgc2F2ZWQgYWxvbmdzaWRlIGl0IChjbGljayB0aGUgKlByZXZpZXcqIGJ1dHRvbiBvciBwcmVzcyAqQ3RybCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLgoKVGhlIHByZXZpZXcgc2hvd3MgeW91IGEgcmVuZGVyZWQgSFRNTCBjb3B5IG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLiBDb25zZXF1ZW50bHksIHVubGlrZSAqS25pdCosICpQcmV2aWV3KiBkb2VzIG5vdCBydW4gYW55IFIgY29kZSBjaHVua3MuIEluc3RlYWQsIHRoZSBvdXRwdXQgb2YgdGhlIGNodW5rIHdoZW4gaXQgd2FzIGxhc3QgcnVuIGluIHRoZSBlZGl0b3IgaXMgZGlzcGxheWVkLgo=